﻿using System.Collections.Generic;
using BlawkayEngine;
using BlawkayEngine.ScreenSystem;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Net;

namespace BlawkayHockey
{
    class GameplayScreen : Screen
    {

        public GameplayScreen(Game oGame)
            : base(oGame)
        {
            _Camera = new Camera();
            _Camera.UpdateViewMatrix();
            _Camera.UpdateProjectionMatrix();
            _Grid = new Grid(oGame);
            _Arena = new Arena(oGame);
            _PersonA = new Person(oGame, new Vector3(0, 0, 20), false);
            _PersonB = new Person(oGame, new Vector3(0, 0, -20), true);

            _People = new List<Person>();
            _People.Add(_PersonA);
            _People.Add(_PersonB);
        }

        public override void Update(ScreenManager oManager)
        {
            Game oGame = oManager.Game;
            _Camera.Update(oGame, _PersonA.Position);
            _Arena.Update(oGame, _Camera);

            if (Networking.IsSessionRunning)
                UpdateNetworkGame();
            else
                UpdateLocalGame();
        }


        void UpdateLocalGame()
        {
            UpdatePersonCollision();
            UpdatePeople();
        }

        void UpdateNetworkGame()
        {
            if (Networking.Session.IsHost)
            {
                HostReadsFromAll();

                UpdatePersonCollision();
                UpdatePeople();

                HostSendsToAll();
            }
            else
            {
                ClientReadsFromHost();

                UpdatePeople();

                ClientSendsToHost();
            }
        }



        void ClientSendsToHost()
        {
            if (Networking.IsSessionRunning == false)
                return;

            Vector3 oDir = _PersonB.Direction;
            byte oType = 0;

            List<object> oMessage = new List<object>();
            byte oPlayerIndex = 1;
            oMessage.Add(oPlayerIndex);
            oMessage.Add((float)oDir.X);
            oMessage.Add((float)oDir.Y);
            oMessage.Add((float)oDir.Z);

            Networking.WriteDataToHost(oType, oMessage);
        }

        void HostReadsFromAll()
        {
            if (Networking.Session == null)
                return;

            NetworkSession oSession = Networking.Session;
            PacketReader oReader = Networking._PackerReader;

            foreach (Person oPerson in _People)
            {
                oPerson.SetRemote(false);
            }

            foreach (LocalNetworkGamer oGamer in oSession.LocalGamers)
            {
                NetworkGamer sender;

                while (oGamer.IsDataAvailable)
                {
                    // Read a single packet.
                    oGamer.ReceiveData(oReader, out sender);

                    if (sender.IsLocal)
                        continue;

                    byte oMessageType = oReader.ReadByte();

                    byte oPlayerIndex = oReader.ReadByte();
                    Person oPerson = _People[oPlayerIndex];

                    Vector3 oDirection = Vector3.Zero;
                    oDirection.X = oReader.ReadSingle();
                    oDirection.Y = oReader.ReadSingle();
                    oDirection.Z = oReader.ReadSingle();

                    oPerson.SetDirection(oDirection);
                    oPerson.SetRemote(true);
                }
            }
        }

        void HostSendsToAll()
        {
            if (Networking.IsSessionRunning == false)
                return;

            List<object> oMessage = new List<object>();

            for (int i = 0; i < _People.Count; i++)
            {
                Vector3 oPos = _People[i].Position;

                oMessage.Add((byte)i);
                oMessage.Add((float)oPos.X);
                oMessage.Add((float)oPos.Y);
                oMessage.Add((float)oPos.Z);
            }

            byte oType = 1;
            Networking.WriteDataToAll(oType, oMessage);
        }

        void ClientReadsFromHost()
        {
            if (Networking.Session == null)
                return;

            NetworkSession oSession = Networking.Session;
            PacketReader oReader = Networking._PackerReader;
            foreach (LocalNetworkGamer oGamer in oSession.LocalGamers)
            {
                NetworkGamer sender;

                while (oGamer.IsDataAvailable)
                {
                    oGamer.ReceiveData(oReader, out sender);

                    if (sender.IsLocal)
                        continue;

                    byte oMessageType = oReader.ReadByte();

                    byte oPlayerIndex;
                    Person oPerson;
                    Vector3 oPosition;

                    oPlayerIndex = oReader.ReadByte();
                    oPerson = _People[oPlayerIndex];
                    oPosition = Vector3.Zero;
                    oPosition.X = oReader.ReadSingle();
                    oPosition.Y = oReader.ReadSingle();
                    oPosition.Z = oReader.ReadSingle();

                    oPlayerIndex = oReader.ReadByte();
                    oPerson = _People[oPlayerIndex];
                    oPosition = Vector3.Zero;
                    oPosition.X = oReader.ReadSingle();
                    oPosition.Y = oReader.ReadSingle();
                    oPosition.Z = oReader.ReadSingle();

                    oPerson.SetPosition(oPosition);
                }

            }
        }

        public override void Draw(ScreenManager oManager, SpriteBatch oSB)
        {
            Game oGame = oManager.Game;
            DepthStencilState depthBufferState;

            depthBufferState = new DepthStencilState();
            depthBufferState.DepthBufferEnable = true;
            oGame.GraphicsDevice.DepthStencilState = depthBufferState;

            _PersonA.DrawOpaque(oGame);
            _PersonB.DrawOpaque(oGame);
            _Arena.DrawOpaque(oGame);

            depthBufferState = new DepthStencilState();
            depthBufferState.DepthBufferEnable = true;
            depthBufferState.DepthBufferWriteEnable = true;
            oGame.GraphicsDevice.DepthStencilState = depthBufferState;

            _PersonA.DrawAlpha(oGame);
            _PersonB.DrawAlpha(oGame);
            _Arena.DrawAlpha(oGame);

            if (GameInfo.IsDebug)
            {
                depthBufferState = new DepthStencilState();
                depthBufferState.DepthBufferWriteEnable = false;
                oGame.GraphicsDevice.DepthStencilState = depthBufferState;

                _Grid.Draw(oGame, _Camera);
                _Camera.Draw(oGame);
            }
        }

        public override void ActionWhenFullyAdded(ScreenManager oManager)
        {
        }

        public override void ActionWhenFullyRemoved(ScreenManager oManager)
        {
        }

        private void UpdatePersonCollision()
        {
            for (int i = 0; i < _People.Count; i++)
            {
                Person A = _People[i];
                for (int j = i + 1; j < _People.Count; j++)
                {
                    Person B = _People[j];
                    Person.CheckCollision(ref A, ref B);
                }

                Person.CheckCollision(ref A, _Arena);
            }
        }

        private void UpdatePeople()
        {

            for (int i = 0; i < _People.Count; i++)
            {
                if (Networking.IsSessionRunning)
                {
                    if (Networking.Session.IsHost)
                    {
                        _People[i].Update(_Camera);
                    }
                    else
                    {
                        if (i == 1)
                            _People[i].Update(_Camera);
                    }
                }
                else
                {
                    _People[i].Update(_Camera);
                }
            }
        }

        Grid _Grid;
        Camera _Camera;
        Arena _Arena;

        List<Person> _People;
        Person _PersonA;
        Person _PersonB;

        // Puck
        // Goals3
        // UI
        // Background

    }
}
